package com.springboot;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.web.servlet.resource.ResourceUrlProvider;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Optional;

/**
 * @author yexi
 */
@SpringBootApplication
@Slf4j
public class WebApplication {

    /**
     * spring-boot-starter-web 创建出 Tomcat 的流程
     *
     * @see SpringApplication#SpringApplication(ResourceLoader, Class[]) 初始化
     * @see WebApplicationType#deduceFromClasspath() SpringApplication 初始化时调用，判断对应类是否存在，若存在则返回 WebApplicationType#SERVLET
     * @see SpringApplication#run(String...) 这里的 main 调用
     * @see SpringApplication#createApplicationContext() 由于是 WebApplicationType#SERVLET 故而创建 ServletWebServerApplicationContext
     * @see ServletWebServerApplicationContext#createWebServer() 创建 Web 服务器，获取到 Tomcat工厂
     * @see TomcatServletWebServerFactory#getWebServer(ServletContextInitializer...) 创建 Tomcat 实例
     */
    public static void main(String[] args) throws UnknownHostException {
        ConfigurableApplicationContext context = new SpringApplication(WebApplication.class).run(args);
        log.info("ApplicationContext实例: {}", context.getClass());
        ServerProperties serverBean = context.getBean(ServerProperties.class);
        Integer port = serverBean.getPort();
        String hostAddress = InetAddress.getLocalHost().getHostAddress();
        /**
         * spring-boot-autoconfigure 设置欢迎页的流程
         * @see WebMvcAutoConfiguration.EnableWebMvcConfiguration#welcomePageHandlerMapping(ApplicationContext, FormattingConversionService, ResourceUrlProvider)
         * @see WebMvcAutoConfiguration.EnableWebMvcConfiguration#getWelcomePage()
         * @see WebProperties.Resources#CLASSPATH_RESOURCE_LOCATIONS 从这几个地方
         * @see WebMvcAutoConfiguration.EnableWebMvcConfiguration#getIndexHtml(Resource)
         */
        log.info("服务已启动，接口测试主页: http://{}:{}", hostAddress, Optional.ofNullable(port).orElse(8080));
    }
}